#include <sstream>
#include "ndn-cxx/encoding/buffer-stream.hpp"
#include "ndn-cxx/security/transform.hpp"
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/security/v2/additional-description.hpp>
#include <ndn-cxx/security/transform/public-key.hpp>
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/security/verification-helpers.hpp>
#include <jsoncpp/json/json.h>

#include "ndnKeyTool.h"

using namespace ndn;

NDNKeyTool::NDNKeyTool(){} ;
NDNKeyTool::~NDNKeyTool(){} ;

static bool isValidBlock(const string& str){
	namespace t = ndn::security::transform;
	try{
		OBufferStream os;
		std::istringstream is(str) ;
		t::streamSource(is) >> t::stripSpace("\n") >> t::base64Decode(false)
			>> t::streamSink(os);
		Block b(os.buf()) ;
	}catch(...){
		return false ;
	}
	return true ;
}

int NDNKeyTool::verifySign(string jsonstr){
	Json::Reader reader ;
	Json::Value root ;

	reader.parse(jsonstr,root) ;
	string sig = root["Sig"].asString() ;
	root.removeMember("Sig") ;
	
	int msgLen = root.toStyledString().size() ;
	char *buf = new char[msgLen] ;
	memcpy(buf , root.toStyledString().data() , msgLen) ;
	delete buf ;
	return 0 ;
}

int NDNKeyTool::verifySign(string jsonstr, string certStr){
	Json::Reader reader ;
	Json::Value root ;

	if(!isValidBlock(certStr)) return -1 ;
	std::stringstream ss ;
	ss << certStr ;
	security::v2::Certificate cert ;
	try{
		cert = *(io::load<security::v2::Certificate>(ss)) ;
	}catch(...){
		return -1 ;
	}
	const Buffer PublicKeyBits = cert.getPublicKey() ;
	security::v2::PublicKey pKey ;
	pKey.loadPkcs8(PublicKeyBits.data(), PublicKeyBits.size()) ;

	std::stringstream signSS ;

	try{
		reader.parse(jsonstr,root) ;
	}catch(...){
		return -2 ;
	}

	signSS << root["Sig"].asString() ;
	root.removeMember("Sig") ;
	optional<Block> signPtr = io::loadBlock(signSS) ;
	
	int msgLen = root.toStyledString().size() ;
	uint8_t *buf = new uint8_t[msgLen] ;
	memcpy(buf , root.toStyledString().data() , msgLen) ;

	bool ret = false;
	ret = ndn::security::verifySignature(buf , msgLen ,
			signPtr->value(), signPtr->value_size() , pKey) ;

	delete buf ;
	return ret ;
}


string NDNKeyTool::signCert(string signRequest){

	if(!isValidBlock(signRequest)) return "" ;

	security::v2::KeyChain keyChain ;
	vector<string> infos ;
	string issuerId = "BlockChain";
	security::v2::AdditionalDescription additionalDescription ;

	std::stringstream ss ;
	ss << signRequest ;
	security::v2::Certificate certRequest ;

	try{
		certRequest = *(io::load<security::v2::Certificate>(ss)) ;
	}catch(std::exception e){
		return "" ;
	}
	time::system_clock::TimePoint notBefore;
	time::system_clock::TimePoint notAfter;
    notBefore = time::system_clock::now();
    notAfter = notBefore + 365_days;

	security::v2::Certificate cert ;
	Name certName = certRequest.getKeyName() ;
	certName.append(issuerId).appendVersion() ;

	cert.setName(certName) ;
	cert.setContent(certRequest.getContent()) ;
	cert.setFreshnessPeriod(1_h) ;

	SignatureInfo signatureInfo ;
	signatureInfo
		.setValidityPeriod( security::ValidityPeriod(notBefore,notAfter) ) ;
	if (!additionalDescription.empty()) {
		signatureInfo.appendTypeSpecificTlv(additionalDescription.wireEncode());
	}

	// 使用默认密钥签名
	security::Identity signIdentity = keyChain.getPib().getDefaultIdentity() ;
	keyChain.sign(cert , security::SigningInfo(signIdentity)
			.setSignatureInfo(signatureInfo)) ;

	std::stringstream oss ;
	io::save(cert, oss) ;
	return oss.str() ;
}
